package YAPserver.gameObjects;

import YAPenvironment.YAPconstant;
import YAPenvironment.YAPconstant.ModState;
import YAPserver.logic.Game;
import YAPserver.logic.GameModifier;
import YAPserver.logic.Player;
import YAPserver.mods.ModBehaviour;
/**
 * Mods are types of balls that interact differently with players. If a player catches a mod with his slider the mod activates by calling its modBehaviour's
 * modify() method that changes an aspect of the game. 
 * @see ModBehaviour
 * @author Daniel
 *
 */
public class Mod extends AbstractBall {
	/* number of ticks the mod waits once activated before deactivating
	 * when tick == 0 -> deactivate
	 * bear in mind not all Mods deactivate... 
	 */
	private int m_ticks = (int) Math.round(Game.m_fps*YAPconstant.C_MODLIFE/30.);
	//when the timer is active the ticks get smaller
	private boolean m_timerOn;
	private boolean m_isActive;
	
	private ModState m_modType;
	
	private ModBehaviour m_modBehaviour;
	// it would probably be best to update the gameModel before the mod is activated
	private GameModifier m_gameMod;
	
	/**
	 * Constructs a mod with position, direction, speed and size.
	 * @param middlePoint point which determines the position at which the ballAbstract will be constructed
	 * @param angle double which determines the direction of the ballAbstract
	 * @param speed double which determines the ballAbstract's speed
	 * @param radius double which determines the ballAbstract's radius
	 */
	public Mod(Point middlePoint, double angle, double speed, double radius,
			GameModifier gameMod, ModBehaviour modBehaviour) {
		super(middlePoint, angle, speed, radius);
		m_timerOn = false;
		m_isActive = false;
		m_gameMod = gameMod;
		m_modBehaviour = modBehaviour;
		m_modType = modBehaviour.getType();
	}

	/**
	 * Causes this mod to activate and change some aspect of the game.
	 * @param player player to whom this mod will be activated
	 * @see ModBehaviour
	 */
	public void activate(Player player){
		m_modBehaviour.modify(this, m_gameMod, player);
		this.addObserver(player);
		m_gameMod.addModActive(this);
		/* TODO remove THIS from gameModel.visibleMods list and add to gameModel.modsMoving list
		 * that is through the modify method of its behaviour
		 * (the gameModel calls isActivated() and if so then removes etc...)
		 * (TODO setSpeed to null and setPosition to null or something like that)
		 */
		setActivated(true);
	}
	/**
	 * Reverts the effect of this mod (if the mod is revertable) for the specified player.
	 * @param player player to whom this mod will be deactivated
	 */
	//when deactivated it will be deleted from the list of GameObjects
	public void deactivate(Player player){
		m_modBehaviour.deModify(this, m_gameMod, player);
		//very important to remove from active mods list
		m_gameMod.removeModActive(this);
		//very important to kill all links
		this.deleteObservers();
		//TODO remove THIS from gameModel.invisibleMods list but probably through the gameModel
		setActivated(false);
	}
	
	/**
	 * Returns true if this mod is activated.
	 * @return <code>true</code> if this mod is activated
	 */
	public boolean isActivated(){
		return m_isActive;
	}
	
	/**
	 * Sets this mod as either activated or deactivated.
	 * @param isActive boolean stating active or not
	 */
	public void setActivated(boolean isActive){
		m_isActive = isActive;
	}
	
	/**
	 * Ticks a mod. The number of ticks this mod has is reduced by one. When the timer reaches 0 the mod automatically deactivates.
	 */
	public void tick(){
		if(m_timerOn){
			m_ticks = m_ticks-1;
			if(m_ticks <= 0){
				setChanged();
				//just some argument so that it doesn't parse null
				//once the Observer is notified the Mod is deactivated
				notifyObservers(this);
			}
		}
	}
	
	/**
	 * Returns the number of ticks this mod has left.
	 * @return the number of ticks this mod has left
	 */
	public int getTicks(){
		return (int) Math.round(30*m_ticks/Game.m_fps);
	}
	/**
	 * Sets the number of ticks this mod has
	 * @param ticks nummber of ticks this mod will have
	 */
	public void setTicks(int ticks){
		m_ticks = (int) Math.round(Game.m_fps*ticks/30);
	}
	
	/**
	 * Sets the timer on or off. If the timer is set to off(false) then if the tick() method is called nothing will happen. The timer won't work when set to off.
	 * @param on boolean if true then the timer will start ticking and if false will not
	 */
	public void setTimerOn(boolean on){
		m_timerOn = on;
	}

	@Override
	public String toString(){
		String s = "";
		s = s + this.m_middlePoint + tab + Math.round(this.m_radius) + tab + m_modType.getValue();
		return s;
	}
}
